#include <irrKlang.h>
#include "stdafx.h"
#include "OgreGpuCommandBufferFlush.h"
#include <parseScene.h>
#include <baloon.h>
#include "Gorilla.h"
#include "mainMenu.h"
#include "PagedGeometry.h"
#include "BatchPage.h"
#include "ImpostorPage.h"
#include "TreeLoader3D.h"
#include "GrassLoader.h"
#include "lvl_update.h"
#include "levels.h"
#include "NxOgreTimestep.h"

using namespace Ogre;


class MainListener : public FrameListener, public OIS::MouseListener, public OIS::KeyListener
{
public:
    MainListener(OIS::Keyboard *keyboard, OIS::Mouse *mouse,SceneManager * sceneMgr,NxOgre::World* m_World,NxOgre::Scene* m_Scene,
			    	Critter::RenderSystem*  m_RenderSystem, Ogre::Root *mRoot)
       
    {
		mBufferFlush.start(1);
		engine = irrklang::createIrrKlangDevice();
		mSceneMgr=sceneMgr;
		mWindow=mRoot->getAutoCreatedWindow();
		//music->getSoundEffectControl()->enableEchoSoundEffect();
		engine->setListenerPosition(irrklang::vec3df(0,0,0), irrklang::vec3df(0,0,1));

		mWorld=m_World;
		mScene=m_Scene;
		mRenderSystem=m_RenderSystem;

		hybX=0;
		hybY=0;
		count=0;
	    m_update = 1.0/60.0;
		m_elapsed = 0.0f;
		mCamera=mSceneMgr->getCamera("Camera");
		//mCamera->setAutoAspectRatio(true);
		mKeyboard=keyboard;
		mMouse=mouse;
		 if (mMouse)
            mMouse->setEventCallback(this);
		 if (mKeyboard)
            mKeyboard->setEventCallback(this);

		  NxOgre::Material* mDefaultMaterial = mScene->getMaterial(0);
		  mDefaultMaterial->setRestitution(0);
		  mDefaultMaterial->setDynamicFriction(0.2);
		  mDefaultMaterial->setStaticFriction(0.2);

		  NxOgre::MaterialDescription ide_m;
		  ide_m.mRestitution=0;
		  ide_m.mDynamicFriction=0;
		  ide_m.mStaticFriction=0;
		  
		  mScene->createMaterial(ide_m);

		  NxOgre::MaterialDescription stoji_m;
		  stoji_m.mRestitution=0;
		  stoji_m.mDynamicFriction=10;
		  stoji_m.mStaticFriction=10;
		  
		  mScene->createMaterial(stoji_m);

/*
	OgreNewt::MaterialPair* material_pair = new OgreNewt::MaterialPair( mWorld, ide_mat, mWorld->getDefaultMaterialID() );
     material_pair->setDefaultFriction(0.0, 0.0f);
     material_pair->setDefaultSoftness(1.5);
     material_pair->setDefaultElasticity(0);
	
	 material_pair = new OgreNewt::MaterialPair( mWorld, ide_mat, flag_mat );
     material_pair->setDefaultCollidable(0);
	
	 material_pair = new OgreNewt::MaterialPair( mWorld, stoji_mat, flag_mat );
     material_pair->setDefaultCollidable(0);

	OgreNewt::MaterialPair* material_pair2 = new OgreNewt::MaterialPair( mWorld, stoji_mat, mWorld->getDefaultMaterialID() );
     material_pair2->setDefaultFriction(2.0, 2.0f);
     material_pair2->setDefaultSoftness(0);
     material_pair2->setDefaultElasticity(0);

	 material_pair2 = new OgreNewt::MaterialPair( mWorld,  mWorld->getDefaultMaterialID(), mWorld->getDefaultMaterialID() );
     material_pair2->setDefaultFriction(0.8, 0.8f);
     material_pair2->setDefaultSoftness(0.1);
     material_pair2->setDefaultElasticity(0.1);
*/
		
					myMenu=new mainMenu(mSceneMgr,mCamera,mWindow,mRoot->getRenderSystem());
					myMenu->setMainMenu();
					gameState=MENU;

					lvlUpdate=NULL;
					

					//p= new Player(mSceneMgr,mWorld,stoji_mat,ide_mat,flag_mat,engine);
					//createLevel2(mSceneMgr,mWorld,flag_mat,&lvlUpdate,p);
					
					createMenuLevel(mSceneMgr,mWorld,mScene,mRenderSystem,&lvlUpdate);

/*
		Entity* ent = mSceneMgr->createEntity( "vytahmesh", "vytah.mesh" );
		OgreNewt::ConvexCollisionPtr col = OgreNewt::ConvexCollisionPtr(new OgreNewt::CollisionPrimitives::ConvexHull(mWorld,ent,1));
	
	vytah = new OgreNewt::Body( mWorld, col );

	SceneNode* vnode = mSceneMgr->getRootSceneNode()->createChildSceneNode();
	vnode->attachObject( ent );

	Vector3 inertia, offset;
    col->calculateInertialMatrix(inertia, offset);
#ifdef OGRENEWT_NO_COLLISION_SHAREDPTR
			//no longer need the collision shape object
			delete col;
#endif
			vytah->setMassMatrix( 4, inertia );
            vytah->setCenterOfMass(offset);
			vytah->setCustomForceAndTorqueCallback<MainListener>(&MainListener::vcallback, this);
			//pbody->setContinuousCollisionMode(1);
			vytah->setPositionOrientation( Ogre::Vector3(0.0,40,0.0), Ogre::Quaternion::IDENTITY );
			//vytah->setLinearDamping(0.1);
			vytah->attachNode( vnode );
			OgreNewt::UpVector* uv= new OgreNewt::UpVector(vytah, Vector3::UNIT_Y);
	OgreNewt::UpVector* uv2= new OgreNewt::UpVector(vytah, Vector3::UNIT_Z);
    

	ent = mSceneMgr->createEntity( "vytahmesh2", "vytah.mesh" );
		col = OgreNewt::ConvexCollisionPtr(new OgreNewt::CollisionPrimitives::ConvexHull(mWorld,ent,1));
	
	OgreNewt::Body* vytah2 = new OgreNewt::Body( mWorld, col );

	SceneNode* vnode2 = mSceneMgr->getRootSceneNode()->createChildSceneNode();
	vnode2->attachObject( ent );

    col->calculateInertialMatrix(inertia, offset);
#ifdef OGRENEWT_NO_COLLISION_SHAREDPTR
			//no longer need the collision shape object
			delete col;
#endif
			vytah2->setMassMatrix( 4, inertia );
            vytah2->setCenterOfMass(offset);
			vytah2->setCustomForceAndTorqueCallback<MainListener>(&MainListener::vcallback2, this);
			//pbody->setContinuousCollisionMode(1);
			vytah2->setPositionOrientation( Ogre::Vector3(10.0,0.0,0.0), Ogre::Quaternion::IDENTITY );
			//vytah->setLinearDamping(0.1);
			vytah2->attachNode( vnode2 );
			OgreNewt::UpVector* uv12= new OgreNewt::UpVector(vytah2, Vector3::UNIT_Y);
	OgreNewt::UpVector* uv22= new OgreNewt::UpVector(vytah2, Vector3::UNIT_Z);
*/
/*
	trees = new Forests::PagedGeometry();
	trees->setCamera(mCamera);	//Set the camera so PagedGeometry knows how to calculate LODs
	trees->setPageSize(80);	//Set the size of each page of geometry
	trees->setInfinite();		//Use infinite paging mode
	trees->addDetailLevel<Forests::BatchPage>(100, 20);		//Use batches up to 150 units away, and fade for 30 more units
	trees->addDetailLevel<Forests::ImpostorPage>(200, 25);	//Use impostors up to 400 units, and for for 50 more units
	Forests::TreeLoader3D *treeLoader = new Forests::TreeLoader3D(trees, Forests::TBounds(25, 25,200, 200));
	trees->setPageLoader(treeLoader);	//Assign the "treeLoader" to be used to load geometry for the PagedGeometry instance
	createGrassMesh();
	Entity *myEntity = sceneMgr->createEntity("Tree", "GrassBladesMesh");
	myEntity->setMaterialName("grass");

	Vector3 position;
	Radian yaw;
	Real scale;
	for (int i = 0; i < 500; i++){
		yaw = Degree(Math::RangeRandom(0, 360));
		position.x = Math::RangeRandom(25, 75);
		position.z = Math::RangeRandom(150, 200);
		position.y = 0;
		scale = Math::RangeRandom(0.1f, 0.03f);
		treeLoader->addTree(myEntity, position, yaw, scale);
	}*/

    }


/*
	void vcallback(OgreNewt::Body* me, float timeStep, int threadIndex )
	{
	Real h=me->getPosition().y;
	if(h>40) {h=40; me->setVelocity(Vector3(0,0,0));}
	Real force=(40-h)/1;
	me->addForce(Vector3(0,force,0));
	}

	void vcallback2(OgreNewt::Body* me, float timeStep, int threadIndex )
	{
	me->setVelocity(Vector3(0,vytah->getVelocity().y*-1,0));
	}
*/
    bool frameStarted(const FrameEvent& evt)
    {
		lvlUpdate->updateLvl(evt.timeSinceLastFrame);

		if(gameState==MENU)
		{
		myMenu->updateMenu(evt.timeSinceLastFrame,rebuildMesh);
		}
		else
		{
		NxOgre::buffer<NxOgre::Shape *> shapes;
		NxOgre::SimpleSphere sp;
		sp.mRadius=0.4f;
		sp.mCenter=NxOgre::Vec3(0,100.0f,0);
		
		int count=mScene->overlapSphereShape(NxOgre::SimpleSphere(0.5f,p->getBody()->getGlobalPosition()-NxOgre::Vec3(0,1.5,0)),NxOgre::Enums::ShapesType_Static,2,shapes);
		myMenu->updateFPS(count);
		}


		mKeyboard->capture();
		mMouse->capture();
		
		updateGodRays();

		if(du2>0)
		{
		du2-=evt.timeSinceLastFrame*2.5;
		if(du2<0) du2=0;
		}

		if(gameState==PLAY)
		{
		p->update(evt.timeSinceLastFrame);
		mWorld->advance(evt.timeSinceLastFrame);
		//mScene->render(evt.timeSinceLastFrame);
		Vector3 pos=p->getBody()->getGlobalPosition().as<Vector3>();
		Vector3 or=mCamera->getDerivedOrientation()*Vector3(0,0,1);
		engine->setListenerPosition(irrklang::vec3df(pos.x,pos.y,pos.z), irrklang::vec3df(or.x,or.y,or.z));

/*
			m_elapsed+=evt.timeSinceLastFrame;
			if ((m_elapsed>m_update)&&(m_elapsed<(1.0)))
			{
		    	while(m_elapsed>m_update)
		    	 {mWorld->advance(m_update);
		    	 m_elapsed-=m_update;}
			} else
			{
			if(m_elapsed<m_update)
			{}
			else
		    {mWorld->advance(m_elapsed);
		    m_elapsed=0.0f;}}*/
        
		}
		return cont;
    }

	virtual bool keyPressed(const OIS::KeyEvent &arg) { 
		
		if(gameState==PLAY)
		p->pressedKey(arg);

		if(gameState==MENU)
		{
			if(arg.key==OIS::KC_SPACE) rebuildMesh=!rebuildMesh;
			int a=myMenu->pressedKey(arg);
			if(a==1) cont=false;
		}

		switch (arg.key)
		{
			  /* case OIS::KC_M: 
				   {
						Ogre::Vector3 size( 2, 2,2 );
		Ogre::Real mass = 0.4;
		Entity* ent;
		SceneNode* node;
		Ogre::String name;

		name = "Bodyd "+Ogre::StringConverter::toString( count++ );

		ent = mSceneMgr->createEntity( name, "boxEL.mesh" );
		node = mSceneMgr->getRootSceneNode()->createChildSceneNode( name );
		node->attachObject( ent );
		node->setScale( size );
		ent->setCastShadows(true);
		ent->setMaterialName( "GreyWood" );

		OgreNewt::ConvexCollisionPtr col = OgreNewt::ConvexCollisionPtr(new OgreNewt::CollisionPrimitives::Box( mWorld, size, 0 ));
		OgreNewt::Body* body = new OgreNewt::Body( mWorld, col );

        Ogre::Vector3 inertia, offset;
        col->calculateInertialMatrix(inertia, offset);

		#ifdef OGRENEWT_NO_COLLISION_SHAREDPTR
			delete col;
		#endif

		body->setMassMatrix( mass, mass*inertia );
        body->setCenterOfMass(offset);
		body->attachNode( node );
		body->setType(3);
		body->setStandardForceCallback();
		body->setPositionOrientation( p->getBody()->getPosition()+Vector3(0,5,0), Ogre::Quaternion::IDENTITY );

				   }
			   break;*/

		   case OIS::KC_ESCAPE:
			   cont=false;
			   break;
/*
           case OIS::KC_TAB: 
			   if(gameState==PLAY) 
			   {gameState=PAUSE;
			    p->stopMoving();
			    makePauseMenu();
				mousePointer->yes_background(1);
			   }
			   else
			   if(gameState==PAUSE) 
			   {gameState=PLAY;
			   mLayer->hide();
			   myCaptions.clear();
			   mLayer->destroyAllCaptions();
			   mLayer->destroyAllRectangles();
			   mousePointer->no_background();
			   }
			   break;*/

           default:
              break;
		}
		 return true;	}

    virtual bool keyReleased(const OIS::KeyEvent &arg) { 
		
		if(gameState==PLAY)
		p->releasedKey(arg);

		switch (arg.key)
		{			   
           default:
              break;
		}
		return true; }

	virtual bool mouseMoved(const OIS::MouseEvent &e) { 

		myMenu->mouseMoveUpdate(e.state.X.rel,e.state.Y.rel);

		if(gameState==PLAY)
		p->movedMouse(e);

		hybY=e.state.Y.rel;
		hybX=e.state.X.rel;
	
		return true; }
    virtual bool mousePressed(const OIS::MouseEvent &arg, OIS::MouseButtonID id) { 
		/*
		Vector2 mPos=mousePointer->position();

		std::vector<Gorilla::Caption*>::iterator myIterator;
		for(myIterator = myCaptions.begin(); 
        myIterator != myCaptions.end();
        myIterator++)
		{
			Gorilla::Caption* c=(*myIterator);
			if(c->intersects(mPos))
				c->colour(Ogre::ColourValue(Math::RangeRandom(0,1),Math::RangeRandom(0,1),Math::RangeRandom(0,1)));
		}*/

		if(gameState==PLAY)
		p->pressedMouse(arg,id);
		else
		if(gameState==MENU)
		{
		int i=myMenu->mainMenuPressed();
		if(i==1)
		{	gameState=PLAY;
			//mWorld->destroyScene(mScene);
			mSceneMgr->clearScene();
			p= new Player(mSceneMgr,mWorld,mScene,mRenderSystem,engine);
			p->setPremenne(&du2);
			createLevel2(mSceneMgr,mWorld,mScene,mRenderSystem,&lvlUpdate,p);

		}
		if(i==3)
			cont=false;
		}
		//else
		//if(gameState==PAUSE)
		//pauseMenuPressed();

		return true; }
    virtual bool mouseReleased(const OIS::MouseEvent &arg, OIS::MouseButtonID id) { 
		if(gameState==PLAY)
		p->releasedMouse(arg,id);
		return true; }

/*
	void makePauseMenu()
	{
		mLayer->show();
		Gorilla::Caption* caption = mLayer->createCaption(24, 15, 250 , "RESUME");
		caption->size(150,25);
		caption->colour(Ogre::ColourValue(0.1,0.15,0.3,0.8));
		caption->align(Gorilla::TextAlign_Right);
		myCaptions.push_back(caption);
		caption = mLayer->createCaption(24, 15, 300 , "RESTART");
		caption->size(150,25);
		caption->colour(Ogre::ColourValue(0.1,0.15,0.3,0.8));
		caption->align(Gorilla::TextAlign_Right);
		myCaptions.push_back(caption);
		caption = mLayer->createCaption(24, 15, 350 , "MAIN MENU");
		caption->size(150,25);
		caption->colour(Ogre::ColourValue(0.1,0.15,0.3,0.8));
		caption->align(Gorilla::TextAlign_Right);
		myCaptions.push_back(caption);
		menuBackground = mLayer->createRectangle(0,0, mScreen->getWidth(), mScreen->getHeight());
		menuBackground->background_gradient(Gorilla::Gradient_Diagonal, Gorilla::rgb(255,255,255,1), Gorilla::rgb(30,30,30,255));
	}*/

	
/*
	void pauseMenuPressed()
	{
		Vector2 mPos=mousePointer->position();

		std::vector<Gorilla::Caption*>::iterator myIterator;
		for(myIterator = myCaptions.begin(); 
        myIterator != myCaptions.end();
        myIterator++)
		{
			Gorilla::Caption* c=(*myIterator);
			if(c->intersects(mPos))
			{
				if(Ogre::StringUtil::match(c->text(),"MAIN MENU"))
				{
					delete p;
					mWorld->destroyAllBodies();
					mSceneMgr->clearScene();
					createMenuLevel(mSceneMgr,mWorld,flag_mat,&lvlUpdate);

					myCaptions.clear();
				    mLayer->destroyAllCaptions();
					mLayer->destroyAllRectangles();

					makeMainMenu();
					gameState=MENU;
					return;
				}
				if(Ogre::StringUtil::match(c->text(),"RESUME"))
				{	
					mLayer->hide();
					myCaptions.clear();
				    mLayer->destroyAllCaptions();
					mLayer->destroyAllRectangles();
					mousePointer->no_background();
					gameState=PLAY;
					return;
				}
			}
		}
	}*/

    void updateGodRays()
	{
		Vector3 sunPosition = Vector3(50000, -30000, -40000);
		Vector3 worldViewPosition = mCamera->getViewMatrix() * sunPosition;
		Vector3 hcsPosition = mCamera->getProjectionMatrix() * worldViewPosition;
		Vector2 sunScreenSpacePosition = Vector2(0.5f + (0.5f * hcsPosition.x), 0.5f + (0.5f * -hcsPosition.y));
		godRaysListener->SunScreenSpacePosition = Vector4(sunScreenSpacePosition.x, sunScreenSpacePosition.y, 0, 1);
		Ogre::Real par=(mCamera->getDerivedPosition() - (Vector3(300, 300, 400) * Vector3(-400, 300, 400))).dotProduct(mCamera->getDerivedDirection());
		if (par > -50000)
		du=0.0; else 
		du=(-(par/1000000))*3.5;
	}



private:
    OIS::Keyboard *mKeyboard;
	OIS::Mouse *mMouse;
	irrklang::ISoundEngine* engine; 
	Real hybX,hybY;
	SceneManager * mSceneMgr;
	Camera* mCamera;
	int count;
	NxOgre::World* mWorld;
	NxOgre::Scene* mScene;
	Critter::RenderSystem*  mRenderSystem;
	Player* p;
	Ogre::GpuCommandBufferFlush mBufferFlush;
	Ogre::RenderWindow* mWindow;
	mainMenu* myMenu;
LvlUpdate* lvlUpdate;
Real m_elapsed;
	Real m_update;
};